<?php


namespace app\api\controller\v23;


use app\api\controller\v2\Auth;
use app\common\cachemodel\Fortune;
use app\common\cachemodel\NatalReport;
use app\common\cachemodel\Orders as OrdersCacheModel;
use app\common\cachemodel\OrdersGoods;
use app\common\cachemodel\OrdersLib;
use app\common\cachemodel\Recode;
use app\common\cachemodel\UserCoupon;
use app\common\cachemodel\ZlActivePrizeNumIncRecord;
use app\common\cachemodel\ZlcrContentCheck;
use app\common\cachemodel\ZlcrCustomReportGoods;
use app\common\cachemodel\ZlcrCustomReportQuestion;
use app\common\cachemodel\ZlcrCustomReportQuestionInfo;
use app\common\cachemodel\ZlSynastryReport;
use app\common\cachemodel\ZlTarotRecords;
use app\common\lib\exception\ApiException;
use app\common\lib\PushQueue;
use Exception;
use think\Cache;
use think\Db;
use think\Log;
use think\response\Json;
use app\common\lib\Util;

/**
 * 2.5.2准币控制器
 * Class Coin
 * @package app\api\controller\v14
 */
class Coin extends Auth
{
    protected $msg;

    /**
     * 准币下单
     * @return Json
     * @throws ApiException
     */
    public function coinPay()
    {
        $this->msg = '';
        $param['gids'] = input('param.gids', '');
        $param['order_type'] = input('param.order_type/d', 0);
        $param['param'] = input('param.param', '');
        $param['openid'] = input('param.openid', '');
        $param['password'] = input('param.password/s', '');
        $param['trade_type'] = 4;//准币支付
        //定制报告检测固定问题今日已购买数量
        $customModel = new ZlcrCustomReportGoods();
        $reportNum = $customModel->getGoodsIndexNum();
        if ($param['order_type'] === 15)
        {
            if ($reportNum['switch'] && !$reportNum['num'])
            {
                $pop = [
                    'tips' => "公测阶段每日限量，今日已无购买名额\n请明日再试",
                    'title' => '非常抱歉'
                ];
                return show(config('code.success'), '商品限量', ['pop' => $pop]);
            }
            Cache::set($customModel->custom_report_goods_index_num_cache . date('Ymd'), $reportNum['num'] - 1, 86400);
        }
        $param = OrdersLib::pay_order_param_format($this->user['id'], $param);
        if ($this->msg)
        {
            Log::write('v14准币支付请求参数有误：' . $this->msg, 'notice', true);
            return show(config('code.error'), $this->msg);
        }
        //使用免费券或支付金额小于0
        $data = $this->SaveFreeOrder($param);
        //如果是定制报告，那么发送钉钉通知
        if (15 === $param['order_type'])
        {
            Util::sendZlcrMsg(0, ['准币支付']);
        }
        return show(config('code.success'), '下单成功', ['order_id' => $data]);
    }

    /**
     * 运势下单
     * @param int $rid
     * @param int $start_time
     * @param int $order_type
     * @return bool|int|string
     */
    private function pay_fortune($rid, $start_time, $order_type)
    {
        $arr = [
            'type' => $order_type - 1,
            'rids' => $rid,
            'time' => $start_time,
            'create_time' => $this->request->time(),
        ];
        try
        {
            $fid = (new Fortune())->insertGetId($arr); //每日运势id
        }
        catch (Exception $e)
        {
            return false;
        }

        return $fid;
    }

    /**
     * 添加中间表数据
     * @param $rid
     * @param $gids
     * @param $oid
     * @return bool
     */
    private function insertMiddle($rid, $gids, $oid)
    {
        $array = [];
        foreach ($gids as $k => $v)
        {
            $array[] = [
                'gid' => $v,
                'oid' => $oid,
                'rid' => $rid
            ];
        }
        //中间表
        try
        {
            (new OrdersGoods())->insertAll($array);
        }
        catch (Exception $e)
        {
            return false;
        }

        return true;
    }

    /**
     * 生成订单数据并入队
     * @param $param [cid,rid,start_time,order_type,gids,out_trade_no,reid,extend,goods_info]
     * @return array
     * @throws ApiException
     * @throws Exception
     */
    private function SaveFreeOrder($param)
    {
        $order_type = (int)$param['order_type'];
        $middle_res = true;
        $CouponModel = new UserCoupon();
        $now_time = time();
        $gid = current($param['gids']);
        //订单状态
        $status = OrdersLib::getOrderStatus($param['gids'], (int)$order_type);
        Db::startTrans();
        try
        {
            (new Recode())->UpdateData($this->user['id'], $param['rid'], [], 1);//or_day生成
            //若是运势，则添加运势中间表数据
            if (in_array($order_type, [2, 3, 4], true))
            {
                $middle_res = $this->pay_fortune($param['rid'], $param['start_time'], $order_type);
            }
            if ($middle_res === false)
            {
                throw new ApiException('下单失败,请重新操作');
            }
            //生成订单数据
            $insert = [
                'order_type' => $order_type,
                'uid' => $this->user['id'],
                'gid' => $gid,
                'order_id' => $param['out_trade_no'],
                'reid' => $param['reid'],
                'fid' => $middle_res === true ? 0 : $middle_res,
                'trade_type' => $param['trade_type'],
                'total_amount' => $param['price'],
                'create_time' => $now_time,
                'update_time' => $now_time,
                'pay_time' => $now_time,
                'status' => $status,
                'account' => 0,
                'extend' => $param['extend']
            ];
            // 生成订单到数据库
            $OrdersCacheModel = new OrdersCacheModel();
            //生成订单数据
            $oid = $OrdersCacheModel->SaveData($insert);
            if ($oid === false)
            {
                throw new ApiException('下单失败,请重新操作');
            }
            //添加中间表数据
            if ($param['rid'])
            {
                $middle_res = $this->insertMiddle($param['rid'], $param['gids'], $oid);
                if ($middle_res === false)
                {
                    throw new ApiException('下单失败,请重新操作');
                }
            }
            //商品购买人数自增,教学视频和本命报告根据课程进行缓存数据
            if (in_array($order_type, [6, 7], true))
            {
                $OrdersCacheModel->SaveTotalPrepaidOrder($order_type, $gid);
            } elseif ($order_type === 17)
            {   // 合盘报告 根据gid自增 和gid与关系ID【relation_id】新增 维护两个缓存
                $extend = \GuzzleHttp\json_decode($param['extend'], true);
                $OrdersCacheModel->SaveTotalPrepaidOrder($order_type, $extend['synastry_report']['srid']); // 根据srid自增
                $OrdersCacheModel->SaveTotalPrepaidOrder($order_type, $extend['synastry_report']['srid'], $extend['synastry_report']['relation_id']); // 根据srid与关系ID【relation_id自增
            } else
            {
                $OrdersCacheModel->SaveTotalPrepaidOrder($order_type, 0);
            }

            //修改优惠券状态为已锁定
            if ($param['cid'])
            {
                $res = $CouponModel->use_return($this->user['id'], $param['cid'], ['status' => 1, 'oid' => $oid, 'update_time' => $this->request->time()]);
                if ($res === false)
                {
                    throw new ApiException($CouponModel->getError());
                }
            }

            //生成第三方数据和入队
            switch (true)
            {
                case $order_type === 1://校准生辰入队
                    $this->RecQueue($param['reid'], $oid, $param['out_trade_no']);
                    break;
                case in_array($order_type, [3, 4], true)://运势入队
                    $this->FortuneQueue($this->user['id'], $oid);
                    break;
                case $order_type === 5://地图入队
                    (new PushQueue())->Map($param['out_trade_no']);
                    break;
                case $order_type === 7://本命预测入队
                    $this->NatalQueue($param['rid'], $param['gids'], $param['out_trade_no']);
                    break;
                case $order_type === 8://若是vip，更新vip有效期和生效状态
                    $middle_res = $this->pay_vip($insert, $gid);
                    break;
                case $order_type === 15: //修改问题状态和问题支付时间并入队
                    $questionModel = new ZlcrCustomReportQuestion();
                    //问题入队
                    $questionModel->orderReportQueue($insert['order_id']);
                    break;
                case $order_type === 16 : //修改塔罗记录状态
                    $extend = json_decode($insert['extend'], true);
                    $taroId = $extend['history']['id'];
                    (new ZlTarotRecords())->updateData($taroId, ['status' => 1]);
                    break;
                case $order_type === 17:
                    $this->SynastryQueue($insert, (int)$gid, null);
                    break;

            }
            //更新星力值
            if ($order_type !== 8)
            {   // VIP订单除外 更新星力值，  VIP星力值已经更新过了，禁止重复更新
                OrdersLib::UpdateVipBoon($insert, $gid, true);
            }
            if ($middle_res === false)
            {
                throw new ApiException('下单失败,请重新操作');
            }
            //塔罗记录更新订单编号数据
            if ($order_type === 16)
            {
                (new ZlTarotRecords())->updateData($param['history_id'], ['order_num' => $param['out_trade_no']]);
            }
            //准币余额修改，添加明细记录
            OrdersLib::UpdateCoin($param['out_trade_no'], $param['order_type'], $param['price'], $this->user['id'], 2,$param['trade_type']);
            //更新订单详情缓存
            $OrdersCacheModel->UpdateCache($param['out_trade_no'], $status);
            Db::commit();
        }
        catch (Exception $e)
        {
            Db::rollback();
            Log::write('准币下单失败：' . $e->getMessage() . '【' . $e->getFile() . $e->getLine() . '】', 'error');
            throw new ApiException('下单失败,请重新操作');
        }

        // 开盲盒任务判断
        (new ZlActivePrizeNumIncRecord())->goodsTask($this->user['id'], $gid, $param['out_trade_no']);

        Util::logRealTimeAnalyzeWrite(4, [
            'coin_pay_uid' => $this->user['id'] ?? '',
            'coin_pay_order_id' => $param['out_trade_no'],
            'coin_pay_order_type' => $order_type,//1=>校准生辰 2=>日运 3=>月运 4=>年运 5=>幸运之城 6=>教学视频 7=>本命预测 8=>会员购买 9=>准币充值 10=>祈福充值 11=>赠送
            'coin_pay_total_amount' => $param['price'],
            'coin_pay_gid' => implode('-', $param['gids']),
            'coin_pay_consumer_type' => 2 // 1=>充值 2=>消费,3=>赠送,4=>退款
        ]);

        return $param['out_trade_no'];
    }

    /**
     * 校准生辰入队
     * @param $reid
     * @param $oid
     * @param $out_trade_no
     * @throws Exception
     */
    private function RecQueue($reid, $oid, $out_trade_no)
    {
        (new PushQueue())->Rectification($this->user, $reid, $oid, $out_trade_no);
    }

    /**
     * 运势入队
     * @param $uid
     * @param $oid
     * @return bool|mixed
     * @throws Exception
     */
    private function FortuneQueue($uid, $oid)
    {
        return (new PushQueue)->Fortune(['uid' => $uid, 'oid' => $oid]);
    }

    /**
     * 本命预测入队加结果数据写入
     * @param int $rid
     * @param array $gids
     * @param string $order_id
     * @throws Exception
     */
    private function NatalQueue($rid, $gids, $order_id)
    {
        $NatalReportModel = new NatalReport();
        $NatalReportModel->SaveQueue($this->user['id'], $rid, $gids, $order_id);
    }

    /**
     * 本命预测入队加结果数据写入
     * @param array $orders
     * @param int $unlock_gid
     * @param null $queueDelay 队列延迟时间
     * @throws Exception
     */
    private function SynastryQueue(array $orders, int $unlock_gid, $queueDelay = null)
    {
        $extend = json_decode($orders['extend'], true);
        (new ZlSynastryReport())->SaveQueue($this->user['id'], $unlock_gid, $extend['synastry_report'], $orders['order_id'], $queueDelay);
    }

    /**
     * 会员下单
     * @param $orders
     * @param $gid
     * @return bool
     */
    private function pay_vip($orders, $gid)
    {
        return OrdersLib::UpdateVipStatus($orders, $gid);
    }
}
